#ifndef WXHELPER_H
#define WXHELPER_H
#include <wx/clntdata.h>
#include <boost/bimap.hpp>
#include <vector>
#include <wx/variant.h>
#include "jdbmodule.h"
#include <wx/msw/ole/oleutils.h>
#include <assert.h>
#include <wx/msgdlg.h>

class wxChoice;
bool myConvertOleToVariant(const VARIANTARG& oleVariant, wxVariant& variant, long flags= wxOleConvertVariant_Default);
template<typename T>
class TClientData : public wxClientData
{
public:
    TClientData() : m_data() { }
    TClientData( const T &data ) : m_data(data) { }
    inline void SetData( const T &data ) { m_data = data; }
    inline const T& GetData() const { return m_data; }
    virtual ~TClientData(){

    }
    inline static TClientData * FromClientData(wxClientData * pcd)
    {
        return static_cast<TClientData*>(pcd);
    }
    inline static TClientData* New(const T & t)
    {
        return new TClientData(t);
    }

private:
    T  m_data;
};

int wxFillChoice(wxChoice * pwnd,ado::ConnectionPtr  pcon,const wchar_t * sql,
                      const wchar_t* key=NULL,const wchar_t * value=NULL,int defSel=0);

int wxFillChoice2(wxChoice * pwnd,ado::ConnectionPtr  pcon,const wchar_t * sql,
                      const wchar_t* key=NULL,const wchar_t * value=NULL,const wchar_t* defVAl=NULL);

inline _bstr_t var2bstr(const _variant_t & var_)
{
    if(var_.vt==VT_EMPTY || var_.vt==VT_NULL)
    {
        return _bstr_t(L"[空]");
    }else{
        return _bstr_t(var_);
    }
}
class wxTable
{
public:
    typedef boost::bimap<std::wstring,long> StringIndexMap;
    typedef std::shared_ptr<StringIndexMap> StringIndexMapPtr;
    typedef std::shared_ptr<_variant_t> RowDataPtr;
    typedef std::vector<RowDataPtr> Table;
    typedef std::shared_ptr<Table> TablePtr;
    class Row
    {
    protected:
        long              m_index;
        StringIndexMapPtr m_simap;
        RowDataPtr        m_rowData;
    public:
        typedef std::shared_ptr<Row> RowPtr;
        inline Row(long row_idx,StringIndexMapPtr & sim,RowDataPtr & data)
            :m_index(row_idx),m_simap(sim),m_rowData(data){}

        inline std::wstring getIndexName(long n)const
        {
            auto pos=m_simap->right.find(n);
            assert(pos!=m_simap->right.end());
            return pos->second;
        }
        inline long getKeyIndex(const std::wstring & key)const
        {
            auto pos=m_simap->left.find(key);
            assert(pos!=m_simap->left.end());
            return pos->second;
        }
        inline RowDataPtr getRowData(){return m_rowData;}
        inline void setRowData(RowDataPtr & rd){m_rowData=rd;}
        long  GetFieldsCount()const
        {return m_simap->size();}

        inline const _variant_t & getFieldValue(long idx)const
        {return m_rowData.get()[idx];}
        inline _variant_t & getFieldValue(long idx)
        {return m_rowData.get()[idx];}
        inline void setFieldValue(long idx,const _variant_t & var)
        {m_rowData.get()[idx]=var;}

        inline const _variant_t & getFieldValue(const std::wstring & idx)const
        {return m_rowData.get()[this->getKeyIndex(idx)];}
        inline _variant_t & getFieldValue(const std::wstring & idx)
        {return m_rowData.get()[this->getKeyIndex(idx)];}
        inline void setFieldValue(const std::wstring & idx,const _variant_t & var)
        {m_rowData.get()[this->getKeyIndex(idx)]=var;}

        static inline RowPtr New(long row_idx,StringIndexMapPtr & sim,RowDataPtr & data)
        {return RowPtr(new Row(row_idx,sim,data));}
    };

public:
    static inline RowDataPtr NewRowData(size_t nsz)
    {return RowDataPtr(new _variant_t[nsz],std::default_delete<_variant_t[]>());}
public:
    StringIndexMapPtr m_keymap;
    TablePtr m_data;
public:

    wxTable();
    ~wxTable();
    void Clear();
    void FillData(ado::ConnectionPtr con,const wchar_t * sql);
    void FillData(ado::ConnectionPtr con,const wchar_t * sql,std::function<bool(Row::RowPtr & row)> cbf);

    inline long  GetFieldsCount()const{return m_keymap->size();}
    inline long  GetRowsCount()const{return m_data->size();}
    inline Row::RowPtr GetRow(long idx)
    {return Row::New(idx,m_keymap,(*m_data)[idx]);}
    inline RowDataPtr GetRowData(long idx)
    { return (*m_data)[idx];}
    inline _variant_t & Cell(long row,long column)
    {
        return (*m_data)[row].get()[column];
    }
    inline const _variant_t & Cell(long row,long column)const
    {
        return (*m_data)[row].get()[column];
    }
    inline void setCell(long row,long column,const _variant_t & var)
    {
        (*m_data)[row].get()[column]=var;
    }
};


#endif // WXHELPER_H
